package com.byq.mm.foundation.cluster.server;

import com.byq.mm.abstractx.cluster.provider.ClusterProvider;
import com.byq.mm.abstractx.cluster.server.ClusterServer;
import com.byq.mm.abstractx.device.Device;
import com.byq.mm.abstractx.engine.CoreEnvironment;
import com.byq.mm.abstractx.protocol.Interaction;
import com.byq.mm.foundation.cluster.datatype.AttributeValue;
import com.byq.mm.foundation.cluster.datatype.AttributeValueFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;


abstract public class BasicClusterServer extends ClusterServer {
	protected Map<String, AttributeValue> attributes = new HashMap<String, AttributeValue>();
	protected Map<String, Collection<String>> subscriber = new HashMap<String, Collection<String>>();
	
	
	public BasicClusterServer(String cluster, Device device, CoreEnvironment env) {
		super(cluster, device, env);
		init();
		
	}
	public AttributeValue getAttributeValue(String attributeName) {
		return attributes.get(attributeName);
	}
//	public void attributeChange(String attributeName, AttributeValue value){
//		
//	}
	abstract protected void init();


	abstract protected Class<? extends AttributeValue> getAttributeType(String attributeValue);
	@Override
	public boolean onCommand(Interaction i, String transport) {
		if(i.command.equals(ClusterProvider.Define.ClientCommand.ReadAttribute.COMMAND_NAME)){
			String attributeName = i.attributes.get(ClusterProvider.Define.ClientCommand.ReadAttribute.Parameters.ATTRIBUTE_NAME);
			reportAttribute(attributeName, transport,i.from);
			return true;
			
		}
		if(i.command.equals(ClusterProvider.Define.ClientCommand.WriteAttribute.COMMAND_NAME)){
			writeAttribute(i, transport);
			return true;
			
		}
		if(i.command.equals(ClusterProvider.Define.ClientCommand.Subscribe.COMMAND_NAME)){
			String attributeName = i.attributes.get(ClusterProvider.Define.ClientCommand.Subscribe.Parameters.ATTRIBUTE_NAME);
			
			subscriber.get(attributeName).add(transport);
			reportSubscribe(attributeName,transport);
			return true;
		}
		if(i.command.equals(ClusterProvider.Define.ClientCommand.Unsubscribe.COMMAND_NAME)){
			String attributeName = i.attributes.get(ClusterProvider.Define.ClientCommand.Unsubscribe.Parameters.ATTRIBUTE_NAME);
			subscriber.get(attributeName).remove(transport);
			reportSubscribe(attributeName,transport);
			return true;
		}
		if(i.command.equals(ClusterProvider.Define.ClientCommand.ReadSubscribe.COMMAND_NAME)){
			String attributeName = i.attributes.get(ClusterProvider.Define.ClientCommand.ReadSubscribe.Parameters.ATTRIBUTE_NAME);
			reportSubscribe(attributeName,transport);
			return true;
		}
		
		return false;

	}
	protected void reportAttribute(String attributeName, String transport, String to){
		
		Interaction report = createAttributeReport(attributeName, to);
		this.env.getExtensionManager().sendInteraction(report, transport);
	}
	public void broadcastAttributeToAll(String attributeName){
		
		Interaction report = createAttributeReport(attributeName, null);
		this.env.getExtensionManager().broadcastInteraction(report,this.getAccessController().getWhileList());
	}
	Interaction createAttributeReport(String attributeName, String to){
		AttributeValue attributeValue = attributes.get(attributeName);
		String value = attributeValue.encode();
		Interaction report = this.createReport();
		report.to = to;
		report.command = ClusterProvider.Define.ServerCommand.ReportAttribute.COMMAND_NAME;
		report.attributes.put(attributeName, value);
		report.attributes.put(ClusterProvider.Define.ServerCommand.ReportAttribute.Parameters.ATTRIBUTE_NAME, attributeName);
		return report;
	}
	public  void broadcastAttributeToSubscription(String attributeName){
		
		Interaction report = createAttributeReport(attributeName, null);
		this.env.getExtensionManager().broadcastInteraction(report,subscriber.get(attributeName));
	}
	void writeAttribute(Interaction i, String transport){
		String attributeName = i.attributes.get(ClusterProvider.Define.ClientCommand.WriteAttribute.Parameters.ATTRIBUTE_NAME);
		String attributeValue = i.attributes.get(attributeName);
		AttributeValue value = AttributeValueFactory.decode(getAttributeType(attributeName),attributeValue);
		attributes.put(attributeName, value);
		broadcastAttributeToAll(attributeName);
		attributeWritten(attributeName, value);
	}
	protected void attributeWritten(String attributeName, AttributeValue value) {
		// TODO Auto-generated method stub
		
	}


	void reportSubscribe(String attributeName, String transport){
		boolean subscribed = subscriber.get(attributeName).contains(transport);
		Interaction i = createReport();
		i.command = ClusterProvider.Define.ServerCommand.ReportSubscribe.COMMAND_NAME;
		i.attributes.put(ClusterProvider.Define.ServerCommand.ReportSubscribe.Parameters.ATTRIBUTE_NAME, attributeName);
		
		i.attributes.put(ClusterProvider.Define.ServerCommand.ReportSubscribe.Parameters.SUBSCRIBED, subscribed + "");
		
		this.env.getExtensionManager().sendInteraction(i, transport);
	}
}
